TypeScript 97.4%
SQL 1%
JavaScript 0.9%
CSS 0.6%
1import { withUser, ApiError } from "@/lib/api";2import { exportConversation, EXPORT_FORMATS, type ExportFormat } from "@/lib/conversations/service";3import { APP_URL } from "@/lib/env";45export const dynamic = "force-dynamic";6type P = { id: string };78/**9 * GET /api/conversations/[id]/export?format=json|markdown|txt|html[&download=1][&print=1]10 *11 * - `download=1` → `Content-Disposition: attachment` (default for json/markdown/txt)12 * - html without `download` renders inline (opened in a new tab by the client for "PDF (print)");13 * `print=1` embeds a tiny script that opens the print dialog on load.14 */15export const GET = withUser<P>(16 async ({ req, user }, { id }) => {17 const sp = new URL(req.url).searchParams;18 const format = (sp.get("format") ?? "markdown") as ExportFormat;19 if (!(EXPORT_FORMATS as readonly string[]).includes(format)) throw new ApiError(400, `Unknown format. Use one of: ${EXPORT_FORMATS.join(", ")}`, "BAD_FORMAT");20 const print = sp.get("print") === "1";21 const inline = format === "html" && sp.get("download") !== "1";22 const out = await exportConversation(user.id, id, format, { print, appUrl: APP_URL });23 return new Response(out.body, {24 headers: {25 "Content-Type": out.contentType,26 "Cache-Control": "private, no-store",27 "X-Robots-Tag": "noindex",28 ...(inline ? {} : { "Content-Disposition": `attachment; filename="${out.filename}"` }),29 },30 });31 },32 { limit: { max: 40, windowMs: 60_000, key: "conv-export" } },33);34